A breakpoint will allow you only to examine local variables and to evaluate expressions at the breakpoint. Often, however, tracking down a bug will require a more extensive investigation of the circumstances surrounding the error. The Scheme debugger system provides additional capabilities to aid in debugging.
The history examiner, entered using the debug command, enables you to examine the history of execution of an expression. The environment of any procedure application may then be examined and the interrupted process may be continued from any of the displayed nodes of evaluation.
Calling the debug procedure from within a Scheme breakpoint enters a read-execute loop, which accepts single-character commands which enable you to move backwards and forwards in the history of the expressions which have been evaluated. You can also examine procedures and variables at the different evaluation levels. The prompt is Debug. Just as with where, Scheme prompts for the commands in the mode line at the bottom of the screen.
In order to make good use of the debugger, you must understand the concept of a reduction and a subproblem. The interpreter evaluates an expression by reducing it to a simpler expression. In general, Scheme's evaluation rules designate that evaluation proceeds from one expression to the next by either starting to work on a subexpression of the given expression, or by reducing the entire expression to a new (simpler, or reduced) form. Thus, a history of the successive forms processed during the evaluation of an expression will show a sequence of subproblems, where each subproblem may involve a sequence of reductions. The best way to get a feeling for how reductions and subproblems work is to write some test expressions and play with them using the debug procedure.
Here is a summary of the debug commands.
For a first look at the debugger we will use several of the
common commands just to see how they work. Here is a demonstration.
The application of the procedure fact caused an error. We then called the debugger, which printed the expression whose evaluation caused the error to occur. The ``Subproblem Level'' and the ``Reduction Number'' are ways of numbering expressions in the history. The procedure whose body is currently being evaluated, as well as the arguments passed to it are displayed. The debugger accepts one letter commands which can be listed by typing ?.
The factorial problem above has a simple typo; the letter L is used instead of the number 1 in the if form, resulting in an unbound variable error. The debugger indicates that the error occurred when fact was called with 0 as its argument.
Although the bug in this case is easy to spot, we can look through the evaluation history, to see how the evaluation proceeds. The command H lists a summary of the history.
Lines 4 through 8 printed by the examiner are pieces of the Scheme REP
loop implementation itself, and should be ignored.
The most common error that can be corrected easily from the debugger is an unbound variable error. In this case, there are two possibilities. If you forgot to define the variable you can use the B command to search back through the history until you find the place where the variable should have been defined. Then, use the E command to enter a REP loop, and define the variable.